# -*- coding: utf-8 -*-
"""
Created on Mon Aug 27 12:33:04 2012

@author: Tomek
"""

import CPPparse

class ReplaceType:
    def __init__(self,oldName,oldExtra,oldArray,newName,newExtra,newArray):
        self.OldName=oldName
        self.OldExtra=oldExtra
        self.OldArray=oldArray
        self.NewName=newName
        self.NewExtra=newExtra
        self.NewArray=newArray
    def oldEquals(self,a):
        if a.OldName==self.OldName and a.OldExtra==self.OldExtra and a.OldArray==self.OldArray:
            return True
        return False
def tableEquals(f,s):
    if len(f)!=len(s):
        return False
    for x in range(0,len(f)):
        if f[x]!=s[x]:
            return False
    return True
def tableContains(f,r):
    for x in f:
        if tableEquals(x,r):
            return True
    return False
class ConvertObject:
    def __init__(self,nm,ptr,ref,nor,tmpl):
        self.pointer=ptr=="True"
        self.reference=ref=="True"
        self.definedTemplates=self.parseTemplates(tmpl)
        self.name=nm
        self.normal=nor=="True"
    def merge(self,x):
        if self.name!=x.name:
            return False
        if self.pointer or x.pointer:
            self.pointer=True
        if self.reference or x.reference:
            self.reference=True
        if self.normal or x.normal:
            self.normal=True
        for xx in x.definedTemplates:
            if tableContains(self.definedTemplates,xx)==False:
                self.definedTemplates.append(xx)
    
    def parseTemplates(self,x):
        self.definedTemplates=[]
        defTable=x.split("|")
        for x in defTable:
            p=x.split(";")
            currTbl=[]
            for xx in p:
                currTbl.append(xx)
            self.definedTemplates.append(currTbl)
    def equals(self,a):
        if self.name==a.name:
            return True
        return False
        
class ReplaceTypeArray:
    def __init__(self):
        self.data=[]
    def exist(self,x):
        for p in self.data:
            if p.oldEquals(x):
                return True
        return False
    def append(self,x):
        if self.exist(x)!=True:
            self.data.append(x)
            
class ConvertObjectArray:
    def __init__(self):
        self.data=[]
    def exist(self,x):
        for p in self.data:
            if p.equals(x):
                return True
        return False
    def getFromName(self,n):
        for p in self.data:
            if p.name==n:
                return p
        return None
    def append(self,x):
        if self.exist(x)==False:
            self.data.append(x)
        else:
            for p in self.data:
                if p.equals(x):
                    p.merge(x)
replaceTypes=ReplaceTypeArray()
convertObjects=ConvertObjectArray()
def replaceType(t):
    nt=CPPparse._Type()
    nt.data=t.data
    for r in replaceTypes.data:
        if t["name"]==r.OldName or r.OldName=="__ANY__":
            if t["extra"]==r.OldExtra or r.OldExtra=="__ANY__":
                if t["array"]==r.OldArray or r.OldArray=="__ANY__":
                    if r.NewName!="__SAME__":
                        nt.data["name"]=r.NewName
                    if r.NewExtra!="__SAME__":
                        nt.data["extra"]=r.NewExtra
                    if r.NewArray!="__SAME__":
                        nt.data["array"]=r.NewArray
    for x in range(0,len(nt["templates"])):
        nt["templates"][x]=replaceType(nt["templates"][x])
    nt.reloadFullname()
    return nt

def convertToReplace():
    for c in convertObjects.data:
        
        if c.pointer:
            x=ReplaceType(c.name,"*","__ANY__",c.name+"_LUAPTR","","__SAME__")
            replaceTypes.append(x)
        if c.reference:
            x=ReplaceType(c.name,"&","__ANY__",c.name+"_LUAREF","","__SAME__")
            replaceTypes.append(x)
        if c.normal:
            x=ReplaceType(c.name,"","__ANY__",c.name+"_LUA","","__SAME__")
            replaceTypes.append(x)
def readConfig(fname):
    f=open(fname,"r")
    readConvertType=False
    readReplaceType=False
    data=[]
    ldata=0
    for x in f.readlines():
        x=x.replace("\n","")
        if readConvertType==False and readReplaceType==False:
            if x=="REPLACE_TYPE":
                readReplaceType=True
                ldata=0
                data=[]
            elif x=="CONVERT_OBJECT":
                readConvertType=True
                ldata=0
                data=[]
        elif readConvertType==True:
            if x=="__NONE__":
                x=""
            data.append(x)
            ldata=ldata+1
            if ldata>4:
                pp=ConvertObject(data[0],data[1],data[2],data[3],data[4])
                readConvertType=False
                convertObjects.append(pp)
        elif readReplaceType==True:
            if x=="__NONE__":
                x=""
            data.append(x)
            ldata=ldata+1
            if ldata>5:
                pp=ReplaceType(data[0],data[1],data[2],data[3],data[4],data[5])
                readReplaceType=False
                replaceTypes.append(pp)
    f.close()
    


def readParsingFile(fname):
    ns=[]
    f=open(fname,"r")
    for x in f.readlines():
        rstr=x
        rstr=rstr.replace("\n","")
        nss=CPPparse.parse(rstr,-1)
        ns.append(nss)
    f.close()
    retNs=ns[0]
    
    for x in ns:
        retNs.merge(x,False)
    return retNs
    
    
def checkLuaType(st):
    if st[len(st)-7:]=="_LUAREF" or st[len(st)-7:]=="_LUAPTR" or st[len(st)-4:]=="_LUA":
        return True
    else:
        return False
        
def getTranslatedType(nm,typ,ftype):
    if checkLuaType(typ):
        return ftype+"("+nm+")"
    else:
        return nm

generateComments=True
def printClassBind(c,cname):
    for x in c["constructors"]:
        params=""
        for p in x["parameters"]:
            if params!="":
                params=params+","
            params=params+p["type"]["fullname"]
        print ".def(luabind::constructor<"+params+">())"
    for x in c["fields"]:
        print ".property(\""+x["name"]+"\",&"+cname+"::"+x["name"]+"_PARAMGET,&"+cname+"::"+x["name"]+"_PARAMSET)"
    for x in c["methods"]:
        params=""
        operParams=""
        for p in x["parameters"]:
            if params!="":
                params=params+","
                operParams+","
            params=params+p["type"]["fullname"]
            p["type"].data["const"]=False
            p["type"].reloadFullname()
            operParams=operParams+"luabind::other<"+p["type"]["fullname"]+">()"
        if x["isOperator"]==False:
            print ".def(\""+x["name"]+"\",("+x["returnType"]["fullname"]+"("+cname+"::*)("+params+"))&"+cname+"::"+x["name"]+")"
        else:
            withOper="self"
            if x["operator"]=="()":
                if len(x["parameters"])==1:
                    withOper=withOper+"("+operParams+")"
            else:
                if len(x["parameters"])!=1:
                    withOper=""
                else:
                    if x["operator"]=="+" or x["operator"]=="-" or x["operator"]=="*" or x["operator"]=="/" or x["operator"]=="==" or x["operator"]=="<" or x["operator"]=="<=":
                       withOper=withOper+x["operator"]+operParams
                    else:
                        withOper=""
            if withOper!="": 
                if x["const"]==True:
                    withOper="luabind::const_"+withOper
                else:
                    withOper="luabind::"+withOper
                print ".def("+withOper+")"
        
        
    
def printClassData(c,acType,nam,rnam):
    for x in c["constructors"]:
        params=""
        paramsNOnly=""
        for p in x["parameters"]:
            if params!="":
                params=params+","
                paramsNOnly=paramsNOnly+","
            params=params+p["type"]["fullname"]+" "+p["name"]
            if checkLuaType(p["type"]["name"]):
                cacType="."
                if p["type"]["extra"]=="*":
                    cacType="->"
                
                paramsNOnly=paramsNOnly+p["name"]+cacType+"_LUA_STORE_DATA_"
            else:
                paramsNOnly=paramsNOnly+p["name"]
        print ""
        if generateComments:
            print "//Class constructor with params"+params
        print nam+"("+params+")"
        print "{"
        print "_LUA_STORE_DATA_="+rnam+"("+paramsNOnly+")"
        print "}"
    for x in c["fields"]:
        print ""
        if generateComments:
            print "//Get parameter of "+x["name"]
        print "virtual",x["type"]["fullname"]+" "+x["name"]+"_PARAMGET()"
        print "{"
        print "return",getTranslatedType("_LUA_STORE_DATA_"+acType+x["name"],x["type"]["name"],x["type"]["fullname"])+";"
        print "}"
        print ""
        if generateComments:
            print "//Set parameter of "+x["name"]
        print "virtual","void "+x["name"]+"_PARAMSET("+x["type"]["fullname"]+" setPar)"
        print "{"
        print "_LUA_STORE_DATA_"+acType+x["name"]+"=setPar;"
        print "}"
    for x in c["methods"]:
        params=""
        paramsNOnly=""
        for p in x["parameters"]:
            if params!="":
                params=params+","
                paramsNOnly=paramsNOnly+","
            params=params+p["type"]["fullname"]+" "+p["name"]
            if checkLuaType(p["type"]["name"]):
                cacType="."
                if p["type"]["extra"]=="*":
                    cacType="->"
                
                paramsNOnly=paramsNOnly+p["name"]+cacType+"_LUA_STORE_DATA_"
            else:
                paramsNOnly=paramsNOnly+p["name"]
        print ""
        if generateComments:
            print "//Class method:",x["name"]
        print "virtual",x["returnType"]["fullname"]+" "+x["name"]+"("+params+")"
        print "{"
        if x["returnType"]["fullname"]!="void":
            if x["isOperator"]==False:
                rtp=getTranslatedType("_LUA_STORE_DATA_"+acType+x["name"]+"("+paramsNOnly+")",x["returnType"]["name"],x["returnType"]["fullname"])
                print "return",rtp+";"
            else:
                if params=="":
                    print "return "+getTranslatedType(x["operator"]+"_LUA_STORE_DATA_",x["returnType"]["name"],x["returnType"]["fullname"])+";"
                else:
                    print "return "+getTranslatedType("_LUA_STORE_DATA_"+x["operator"]+paramsNOnly,x["returnType"]["name"],x["returnType"]["fullname"])+";"
        else:
            print "_LUA_STORE_DATA_"+acType+x["name"]+"("+paramsNOnly+")"+";"
        print "}"

def printClass(cp):
    c=CPPparse._Class("","")
    c.data=cp.data
    ctype=convertObjects.getFromName(c["name"])
    if ctype==None:
        return
    nsp=c["namespace"].split("::")
    nameWithTemp=c["name"]
    fullTemp=""
    frst=False
    for x in c.getTemplate():
        if frst==False:
            nameWithTemp=nameWithTemp+"<"
            fullTemp=fullTemp+"<"
            frst=True
        else:
            nameWithTemp=nameWithTemp+","
            fullTemp=fullTemp+","
        fullTemp=fullTemp+"typename "+x
        nameWithTemp=nameWithTemp+x
    if frst:
        fullTemp=fullTemp+">"
        nameWithTemp=nameWithTemp+">"
    for n in nsp:
        if n!="":
            print "namespace",n
            print "{"
    
    if ctype.normal:
        print "//////////////////////////////////////////////////////////////"
        print "//"+c["name"],"class translator generated with DarkLua"
        print "//Please do not edit this :)"
        print "//////////////////////////////////////////////////////////////"
        print fullTemp
        derstr=""
        for d in c["base"]:
            if derstr!="":
                derstr=derstr+","
            derstr=derstr+d[1]+" "+d[0]+"_LUA"
        if derstr!="":
            derstr=": "+derstr
        print "class",c["name"]+"_LUA",derstr
        print "{"
        print "public:"
        print fullTemp
        print "static void __LUAbindClass()"
        print "{"
        printClassBind(c["public"],c["name"]+"_LUA")
        print "}"
        print nameWithTemp+" _LUA_STORE_DATA_;"
        print c["name"]+"_LUA("+nameWithTemp+" _store_data_)"
        print "{"
        print "_LUA_STORE_DATA_=_store_data;"
        print "}"
        printClassData(c["public"],".",c["name"]+"_LUA",nameWithTemp)
        print "private:"
        printClassData(c["private"],".",c["name"]+"_LUA",nameWithTemp)
        print "protected:"
        printClassData(c["protected"],".",c["name"]+"_LUA",nameWithTemp)
        print "};"

    if ctype.pointer:
        print "//////////////////////////////////////////////////////////////"
        print "//"+c["name"],"class pointer generated with DarkLua"
        print "//Please do not edit this :)"
        print "//////////////////////////////////////////////////////////////"
        print fullTemp
        derstr=""
        for d in c["base"]:
            if derstr!="":
                derstr=derstr+","
            derstr=derstr+d[1]+" "+d[0]+"_LUAPTR"
        if derstr!="":
            derstr=": "+derstr
        print "class",c["name"]+"_LUAPTR",derstr
        print "{"
        print "public:"
        print nameWithTemp+" *_LUA_STORE_DATA_;"
        print c["name"]+"_LUAPTR("+nameWithTemp+" *_store_data_)"
        print "{"
        print "_LUA_STORE_DATA_=_store_data;"
        print "}"
        printClassData(c["public"],"->",c["name"]+"_LUAPTR",nameWithTemp)
        print "private:"
        printClassData(c["private"],"->",c["name"]+"_LUAPTR",nameWithTemp)
        print "protected:"
        printClassData(c["protected"],"->",c["name"]+"_LUAPTR",nameWithTemp)
        print "};"
    if ctype.reference:
        print "//////////////////////////////////////////////////////////////"
        print "//"+c["name"],"class reference generated with DarkLua"
        print "//Please do not edit this :)"
        print "//////////////////////////////////////////////////////////////"
        print fullTemp
        derstr=""
        for d in c["base"]:
            if derstr!="":
                derstr=derstr+","
            derstr=derstr+d[1]+" "+d[0]+"_LUAREF"
        if derstr!="":
            derstr=": "+derstr
        print "class",c["name"]+"_LUAREF",derstr
        print "{"
        print "public:"
        print nameWithTemp+" &_LUA_STORE_DATA_;"
        print c["name"]+"_LUAREF("+nameWithTemp+" &_store_data_)"
        print "{"
        print "_LUA_STORE_DATA_=_store_data;"
        print "}"
        printClassData(c["public"],".",c["name"]+"_LUAREF",nameWithTemp)
        print "private:"
        printClassData(c["private"],".",c["name"]+"_LUAREF",nameWithTemp)
        print "protected:"
        printClassData(c["protected"],".",c["name"]+"_LUAREF",nameWithTemp)
        print "};"
    for n in nsp:
        if n!="":
            print "}"
    
configFile="config.txt"
readConfig("scan.txt")
globalNamespace=readParsingFile(configFile)
for x in globalNamespace.getObjects("Type"):
    x=replaceType(x)
convertToReplace()

for x in globalNamespace.getObjects("Type"):
    x=replaceType(x)
for c in globalNamespace.getObjects("Class"):
    if c["public"].isDataEmpty()==False or c["protected"].isDataEmpty()==False or c["private"].isDataEmpty()==False:
        printClass(c)
    else:
        print "Could be but null",c["name"]
        
        